package NetWork;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpEchoServer {

    private ServerSocket serverSocket = null;
    private ServerSocket serverSocket2 = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket   = new ServerSocket(port);
        serverSocket2   = new ServerSocket(port + 1);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");

        //创建线程池
        ExecutorService pool = Executors.newCachedThreadPool();

        while(true){      //主循环:通过accept接收到客户端的连接
            Socket clientSocket = serverSocket.accept();

            //把任务添加到线程池中
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnection(clientSocket);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }) ;

            //引入多线程解决无法同时启动多个客户端的问题
            //但是 代码改成多线程的形式,就不能通过 try() 的方式来关闭 clientSocket了  -> 我们可以在后面的finally里面关闭
//            //否则 就会使 clientSocket 被立即关闭 , 此时 processConnection 还没来得及适应
//            Thread t = new Thread(() ->{
//                try{
//                    //通过processConnection处理客户端连接
//                    processConnection(clientSocket);
//                }catch(IOException e){
//                    e.printStackTrace();
//                }
//            });
//             t.start();
        }
    }

    //处理客户端连接的方法
    private void processConnection(Socket clientSocket) throws IOException {
        //1.打印一个日志,告知当前客户:连上了.
        System.out.printf("[%s:%d] 客户上线~\n", clientSocket.getInetAddress(),clientSocket.getPort());
        //2.从 socket 中获取流对象 , 进一步的进行后续操作
        try(InputStream inputStream = clientSocket.getInputStream();
            OutputStream outputStream = clientSocket.getOutputStream()){

            //3. 也搞一个循环,针对每个连接,客户端都可能会发来多个请求,服务器也需要返回多个响应   (相当于打电话:电话接通以后会发送很多信息)
            Scanner scanner = new Scanner(inputStream);
            while(true){
                //3.1 读取请求并解析
                    //判断一下是否能读取到这个请求
                if(!scanner.hasNext()){
                    //如果发现后续无数据了,此时说明TCP的连接已断开
                    System.out.printf("[%s:%d] 客户端下线!",clientSocket.getInetAddress(),clientSocket.getPort());
                    break;
                }
                //如果能读取请求:
                String request = scanner.next();//
                //3.2根据请求计算响应时间
                String response = process(request);
                //3.3把响应写回客户端
                outputStream.write(response.getBytes(),0,response.getBytes().length);
                //3.4服务器打印日志
                System.out.printf("[%s:%d] req = %s , resp = %s\n",clientSocket.getInetAddress(),clientSocket.getPort(),request,response);
            }
            

        }catch(IOException e){
            e.printStackTrace();
        }finally{
            //在这里关闭(靠谱)
            //即当前 processConnection 在不同线程中被调用 , 也可以正确关闭
            clientSocket.close();//关闭掉客户端,防止信息泄露
        }
    }

    //根据请求计算响应的方法
    private String process(String request){
        //给响应这里后面加上换行符,使客户端读取响应时,也有明确的分隔符
        return request + "\n";
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start();
    }
    
}
